package com.zzq.my.jetpacks.util

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Outline
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.ViewOutlineProvider
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.annotation.NonNull
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ComponentActivity
import androidx.core.content.res.ResourcesCompat
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.ToastUtils
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.zzq.my.jetpacks.base.R
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * 描述：act 常用的扩展函数
 * 作者：zhuangzeqin
 * 时间: 2021/12/22-11:01
 * 邮箱：zzq@eeepay.cn
 * 备注:
 */
fun Activity.goActivity(
    @NonNull context: Context,
    @NonNull descClass: Class<*>,
    bundle: Bundle? = null,
    requestCode: Int = -1,
    flags: Int? = -1
) {
    val javaClass = context.javaClass
    if (javaClass == descClass) {
        return
    }
    kotlin.runCatching {
        val intent = Intent()
        intent.setClass(context, descClass)
        //表示object不为null的条件下，才会去执行let函数体
        flags?.let { intent.addFlags(it) }
        bundle?.let { intent.putExtras(it) }
        //API才发现requestCode >= 0才起作用;如果用负值的requestCode和调用startActivity是一样的，所以代码不走startActivityForResult而是startActivity
        if (requestCode > 0)
            (context as Activity).startActivityForResult(intent, requestCode)
        else
            (context as Activity).startActivity(intent)
        context.overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out)
    }.onSuccess {

    }.onFailure {
        it.printStackTrace()
    }
}

/**
 * 判断数字在某个区间的语法
 */
fun String.isInRegion(min: String?, max: String?): Boolean {
    if (TextUtils.isEmpty(this) || TextUtils.isEmpty(min) || TextUtils.isEmpty(max)) return false
    return (this.toBigDecimal() in min!!.toBigDecimal()..max!!.toBigDecimal())
}
//6~20位，必须包含数字+字母，且支持任意符号
const val ex = "^(?![\\\\d]+\$)(?![a-zA-Z]+\$)(?![^\\\\da-zA-Z]+\$).{6,20}\$"

//可以用扩展函数为 ImageView 添加一个加载图片的方法---imageView.loadImage(url)
fun ImageView.loadImage(url: String, errorResourceId: Int = 0) {
    Glide.with(context).load(url).error(errorResourceId).into(this)
}

fun ImageView.loadImageByCenterCrop(imgUrl: String) {
    //加载原始图片和其他形状的图片形状作为对比。
    Glide.with(context).load(imgUrl).centerCrop().into(this)
    //标准圆形图片。
    Glide.with(context).load(imgUrl).apply(RequestOptions.bitmapTransform(CircleCrop())).into(this);
    // 四周都是圆角的圆角矩形图片。
    Glide.with(context).load(imgUrl).apply(RequestOptions.bitmapTransform(RoundedCorners(20)))
        .into(this);

}

/**
 *  map 转换为数据bean
 */
inline fun <reified T> mapToBean(map: MutableMap<String, Any>): T {
//    val gson = getJsonInit()
//    val gson = GsonUtils()
    val jsonStr = GsonUtils.toJson(map)
    return GsonUtils.fromJson(jsonStr, T::class.java)
}

//获取json的初始化方式
//fun getJsonInit(): Gson {
//    val jsonBuild = GsonBuilder()
//    //加上这行可以过滤服务器返回的null
//    jsonBuild.serializeNulls()
//    return jsonBuild.create()
//}

/**
 * reified,kotlin中的泛型实化关键字，使抽象的东西更加具体或真实。
 * 扩展一个函数  goActivity<RxMainAct>(this);简单的跳转不带任何的参数设置
 */
inline fun <reified T : Activity> Activity.goActivity(@NonNull context: Context) {
    goActivity(context, T::class.java)
}

inline fun <reified T : Activity> Activity.goActivity() {
    goActivity(this, T::class.java)
}

/**
 * Activity 扩展一个可以toast
 * inline 内联对预期性能的影响并不显著。内联最适合于具有功能类型参数的功能
 */
fun Activity.showMsg(msg: String?) {
    val str = msg ?: return
    ToastUtils.showShort(str)
//    msg?.let {
//        ToastUtils.showShort(msg)
//    }
}

fun Fragment.showMsg(msg: String?) {
    val str = msg ?: return
    ToastUtils.showShort(str)
}

/**
 * 隐藏输入法
 */
fun Activity.dismissKeyBoard(view: View) {
    val inputManager = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager?
    inputManager?.hideSoftInputFromWindow(view.windowToken, 0)
}
//endregion

//region 扩展属性
/**
 * 扩展lifeCycleOwner属性，便于和Fragment之间使用lifeCycleOwner 一致性
 */
val ComponentActivity.viewLifeCycleOwner: LifecycleOwner
    get() = this

/**
 * Activity的扩展字段，便于和Fragment中使用liveData之类的时候，参数一致性
 */
val Activity.context: Context
    get() = this

//endregion

/**
 * Activity中使用DataBinding 简化setContentView
 * [layoutId] 布局文件
 * @return 返回一个ViewDataBinding实例
 */
fun <T : ViewDataBinding> Activity.bindView(@LayoutRes layoutId: Int): T {
    return DataBindingUtil.setContentView(this, layoutId)
}

/**
 * Activity中使用DataBinding 简化setContentView
 * [view]
 * @return 返回一个ViewDataBinding实例 可空
 */
fun <T : ViewDataBinding> Activity.bindView(view: View): T? {
    return DataBindingUtil.bind<T>(view)
}

/**
 * 沉浸式状态栏实现
 */
fun Activity.immediateStatusBar() {
    window.apply {
        addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
        addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
        addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
        decorView.systemUiVisibility =
            View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    }
}

//自定义id
inline fun <reified T : View> Activity.getByID(name: String): T {
    val id = resources.getIdentifier(name, "id", packageName)
    return findViewById(id)
}

// 字符串统一格式；如果为空显示-
fun String.strForMat(): String {
    return if (this.isNotEmpty()) this else "-"
}

/**
 * 对 List<T> 定义一个把所有元素以逗号拼接为字符串的扩展函数
 * println(listOf("a", "b", "c").joinToString()) // a, b, c
 */
fun <T> List<T>.joinToString(): String {
    val result = StringBuilder()
    for ((index, element) in this.withIndex()) {
        if (index > 0) result.append(", ")
        result.append(element)
    }
    return result.toString()
}

/**
 * 扩展函数view 防爆点击 事件
 */
inline fun View.setSafeListener(crossinline action: () -> Unit) {
    var lastClick = 0L
    setOnClickListener {
        val gap = System.currentTimeMillis() - lastClick
        lastClick = System.currentTimeMillis()
        if (gap < 1500) return@setOnClickListener//1.5s  重复点击直接return
        action.invoke()
    }
}

/**
 * 倒计时
 * var mCountdownJob: Job? =null
 * mCountdownJob = countDownCoroutines(60, lifecycleScope,
onTick = { second ->
mBinding.text.text = "${second}s后重发"
}, onStart = {
// 倒计时开始
}, onFinish = {
// 倒计时结束，重置状态
mBinding.text.text = "发送验证码"
})

// 取消倒计时
mCountdownJob?.cancel()
 */
fun View.countDownCoroutines(
    total: Int = 60,
    scope: CoroutineScope,
    onStart: () -> Unit,
    onTick: (Int) -> Unit,
    onFinish: () -> Unit
): Job {
    return flow {
        for (i in total downTo 0) {
            emit(i)
            delay(1000)//1s
        }
    }.flowOn(Dispatchers.Main)
        .onStart { onStart.invoke() }
        .onCompletion { onFinish.invoke() }
        .onEach { onTick.invoke(it) }
        .launchIn(scope)

}

fun View.countDownCoroutines2(
    total: Int = 60,
    scope: CoroutineScope,
    mCountBuilder: CountBuilder.() -> Unit
): Job {
    val callBack = CountBuilder().also(mCountBuilder);
    return flow {
        for (i in total downTo 0) {
            emit(i)
            delay(1000)//1s
        }
    }.flowOn(Dispatchers.Main)
        .onStart { callBack.onStart?.invoke() }
        .onCompletion { callBack.onFinish?.invoke() }
        .onEach { callBack.onTick?.invoke(it) }
        .launchIn(scope)
}

class CountBuilder {
    var onStart: (() -> Unit)? = null
    var onTick: ((time: Int) -> Unit)? = null
    var onFinish: (() -> Unit)? = null
}

/**
 * 字符串的追加的dsl
 */
fun String.strDSL(block: StringBuilder.() -> Unit): String {
    return StringBuilder(this).also(block).toString()
}


/**
 * Textview 拓展函数
 * imageId： 资源图片id
 * location: left、top、right、bottom
 * padding: 外部传入的padding值 ，注意统一使用 dip2px转后传入，统一尺寸
 */
fun TextView.setImageDrawable(imageId: Int = 0, location: String, padding: Int = 0) {
    val drawable = ResourcesCompat.getDrawable(resources, imageId, null)
    drawable?.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight)
    if (TextUtils.equals("left", location)) {
        setCompoundDrawables(drawable, null, null, null)
    } else if (TextUtils.equals("top", location)) {
        setCompoundDrawables(null, drawable, null, null)
    } else if (TextUtils.equals("right", location)) {
        setCompoundDrawables(null, null, drawable, null)
    } else if (TextUtils.equals("bottom", location)) {
        setCompoundDrawables(null, null, null, drawable)
    } else {
        setCompoundDrawables(null, null, null, null)
    }
    compoundDrawablePadding = padding

}


/**
 * Activity 协程的扩展函数
 */
fun AppCompatActivity.launchKt(block: suspend CoroutineScope.() -> Unit) {
    lifecycleScope.launch {
        runCatching {
            coroutineScope {
                block.invoke(this)
            }
        }.onFailure {
            it.printStackTrace()
        }
    }
}

/**
 * Activity 协程的扩展函数
 */
fun Fragment.launchKt(block: suspend CoroutineScope.() -> Unit) {
    lifecycleScope.launch {
        runCatching {
            coroutineScope {
                block.invoke(this)
            }
        }.onFailure {
            it.printStackTrace()
        }
    }
}

/**
 *  Activity 协程的扩展函数
 *  asynckt {}.awaitkt(this,{}, {})
 */
fun <T> AppCompatActivity.asynckt(loader: suspend () -> T): Deferred<T?> {
    val deferred = lifecycleScope.async(Dispatchers.IO) {
        runCatching {
            coroutineScope {
                loader.invoke()
            }
        }.onSuccess {
            return@async it
        }.onFailure {
            it.printStackTrace()
        }.getOrNull()
    }
    return deferred
}

/**
 *  Fragment 协程的扩展函数
 *  asynckt {}.awaitkt(this,{}, {})
 */
fun <T> Fragment.asynckt(loader: suspend () -> T): Deferred<T?> {
    val deferred = lifecycleScope.async(Dispatchers.IO) {
        runCatching {
            coroutineScope {
                loader.invoke()
            }
        }.onSuccess {
            return@async it
        }.onFailure {
            it.printStackTrace()
        }.getOrNull()
    }
    return deferred
}

//Deferred类型扩展函数
fun <T> Deferred<T>.awaitkt(
    lifecycleOwner: LifecycleOwner,
    onSuccess: (T) -> Unit,
    onError: (e: Throwable) -> Unit
) {
    lifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
        runCatching {
            this@awaitkt.await()
        }.onSuccess {
            onSuccess.invoke(it)
        }.onFailure {
            it.printStackTrace()
            onError.invoke(it)
        }
    }
}

/**
 * 给View 设置一个圆角
 */
fun View.setCornerRadius(dp: Float) {
    clipToOutline = true
    val px = dp2px(dp)
    outlineProvider = object : ViewOutlineProvider() {
        override fun getOutline(v: View?, outline: Outline?) {
            outline?.setRoundRect(0, 0, v!!.width, v.height, px.toFloat())
        }
    }
}

fun View.dp2px(dipValue: Float): Int {
    val scale = context.resources.displayMetrics.density
    return (dipValue * scale + 0.5f).toInt()
}


/**
 * 内联扩展函数，扩展的是Iterable，
 * 集合的顶层是“public interface Collection<out E> : Iterable<E>”，
 * 即集合都实现了Iterable接口，所以扩展Iterable就意味着所有集合都可以用自定义的扩展函数convert
 *  val list = listOf(1, 2, 3, 4, 5, 6, 7)
//print 2 3 4 5 6 7 8
list.convert { it + 1 }.forEach { print(it) }
 */
inline fun <T, E> Iterable<T>.convert(action: (T) -> E): Iterable<E> {
    //定义一个可变的list
    val list: MutableList<E> = mutableListOf()
    //循环遍历调用扩展函数convert的集合
    for (item: T in this)
    //将修改后的value，add到定义的可变的list中
        list.add(action(item))
    //返回定义的可变list
    return list
}





